﻿using DependencyInjection.StaticAccessor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Rougamo;
using Rougamo.Context;

/// <summary>
/// 只区分到租户级别，店铺请用租户的缓存再查询。
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class CacheableAttribute : MoAttribute
{
    /// <summary>
    /// 只区分到租户级别，店铺请用租户的缓存再查询。 无参数缓存key 取class,method
    /// </summary>
    public CacheableAttribute()
    {
    }

    /// <summary>
    /// 只区分到租户级别，店铺请用租户的缓存再查询。有key时直接取指定的key
    /// </summary>
    /// <param name="share">租户之间共享缓存</param>
    /// <param name="cacheKey"></param>
    public CacheableAttribute(string cacheKey = "")
    {
        CacheKey = cacheKey;
    }


    /// <summary>
    /// 缓存KEY
    /// </summary>
    public string CacheKey { get; set; } = "";


    /// <summary>
    /// 默认10分钟
    /// </summary>
    public int ExpiredSeconds { get; set; } = 60 * 10;


    /* public override void OnEntry(MethodExecutionArgs args)
     {
         Console.WriteLine("On entry");
     }

     public override void OnExit(MethodExecutionArgs args)
     {
         Console.WriteLine("On exit");
     }

     public override void OnException(MethodExecutionArgs args)
     {
         Console.WriteLine("On exception");
     }*/


    private void FixCahceKey(MethodContext context)
    {
        string methodName = context.Method.Name;
        string className = context.TargetType.FullName ?? "";
        List<object> methodArguments = context.Arguments.ToList();

        if (string.IsNullOrWhiteSpace(this.CacheKey))
        {
            string param = "";
            this.CacheKey = "Methods:" + "_" + className + "." + methodName;
            //  Console.WriteLine($"增加缓存主KEY{cacheKey}");
            this.CacheKey = MD5Encrypt.Encrypt16(this.CacheKey);
            if (methodArguments.Count > 0)
            {
                param = "_" + MD5Encrypt.Encrypt16(JSON.Serialize(methodArguments));
            }
            // logger.LogDebug($"缓存Key:{CacheKey},参数:{param}");

            this.CacheKey += param;
        }
    }
    ILogger<CacheableAttribute>? logger;
    private ICache _cache;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    public override void OnEntry(MethodContext context)
    {



        // 从context对象中能取到包括入参、类实例、方法描述等信息
        //logger = App.CreateScopeProvider().GetRequiredService<ILogger<CacheableAttribute>>();
        _cache = context.GetRequiredService<ICache>();
        FixCahceKey(context);
        if (_cache.Exists(CacheKey))
        {
            object? cacheValue = _cache.Get(CacheKey);

            //将当前获取到的缓存值，赋值给当前执行方法
            //如果有缓存则立即返回不执行了。
            //将当前获取到的缓存值，赋值给当前执行方法
            //如果有缓存则立即返回不执行了。
            context.ReplaceReturnValue(this, cacheValue);
            //logger?.LogDebug($"从缓存中读取");

        }

    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(MethodContext context)
    {
    }
    public override void OnSuccess(MethodContext context)
    {
        //缓存结果
        // var _cache = context.GetRequiredService<ICache>();
        //  var logger = context.GetRequiredService<ILogger<CacheableAttribute>>();
        _cache.Set(CacheKey, context.ReturnValue, TimeSpan.FromSeconds(ExpiredSeconds > 0 ? ExpiredSeconds : 10 * 60));

    }


    /*    private async Task<T> InterceptTAsync<T>(ICache _cache, int expired, string cacheKey, Task<T> task)
        {
            T result = await task.ConfigureAwait(false);
            if (expired > 0)
            {
                await _cache.SetAsync(cacheKey, result ?? throw new Exception($"{this.CacheKey} cache can't be empty"), TimeSpan.FromSeconds(expired));
            }
            else
            {
                await _cache.SetAsync(cacheKey, result ?? throw new Exception($"{this.CacheKey} cache can't be empty"), TimeSpan.FromSeconds(10 * 60));
            }
            // await RedisHelper.SetAsync(cacheKey, JsonConvert.SerializeObject(result), ExpireSeconds);
            return result;
        }*/

    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    public override void OnExit(MethodContext context)
    {



    }

}

